package com.supermap.desktop.mapview.layer.propertycontrols;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.concurrent.Callable;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.border.Border;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import com.supermap.desktop.Application;
import com.supermap.desktop.Interface.IFormMap;
import com.supermap.desktop.controls.ControlsProperties;
import com.supermap.desktop.event.ActiveFormChangedEvent;
import com.supermap.desktop.event.ActiveFormChangedListener;
import com.supermap.desktop.event.ActiveLayersChangedEvent;
import com.supermap.desktop.event.ActiveLayersChangedListener;
import com.supermap.desktop.properties.CommonProperties;
import com.supermap.mapping.Layer;
import com.supermap.mapping.Map;

public class LayerPropertyContainer extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private JPanel panelContainer;
	private JCheckBox checkBoxIsAutoApply;
	private JButton buttonApply;
	private IFormMap formMap;

	private ArrayList<AbstractLayerPropertyControl> propertyControls = new ArrayList<AbstractLayerPropertyControl>();

	private LayerPropertyControlUtilties propertyControlUtilties = new LayerPropertyControlUtilties();

	private ActiveLayersChangedListener activeLayersChangedListener = new ActiveLayersChangedListener() {

		@Override
		public void acitiveLayersChanged(ActiveLayersChangedEvent e) {
			activeLayersChanged(e);
		}
	};

	private ChangedListener layerPropertyChangedListener = new ChangedListener() {

		@Override
		public void changed(ChangedEvent e) {
			buttonApply.setEnabled(!checkBoxIsAutoApply.isSelected() && e.getCurrentState() == ChangedEvent.CHANGED);
		}
	};

	/**
	 * Create the panel.
	 */
	public LayerPropertyContainer() {
		initializeComponents();
		initializeResources();
		this.checkBoxIsAutoApply.setSelected(true);
		this.checkBoxIsAutoApply.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent e) {
				checkBoxIsAutoApplyCheckedChanged(e);
			}
		});
		this.buttonApply.setEnabled(false);
		this.buttonApply.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				buttonApplyClicked(e);
			}
		});
		Application.getActiveApplication().getMainFrame().getFormManager().addActiveFormChangedListener(new ActiveFormChangedListener() {

			@Override
			public void activeFormChanged(ActiveFormChangedEvent e) {
				if (e.getNewActiveForm() instanceof IFormMap) {
					setFormMap((IFormMap) e.getNewActiveForm());
				} else {
					setFormMap(null);
				}
			}
		});
	}

	public IFormMap getFormMap() {
		return this.formMap;
	}

	public void setFormMap(IFormMap formMap) {
		if (this.formMap != null) {
			unregisterEvents();
		}
		this.formMap = formMap;
		if (this.formMap != null) {
			setActiveLayers(this.formMap.getActiveLayers(), this.formMap.getMapControl().getMap());
			registerEvents();
		}
	}

	private void initializeComponents() {
		this.panelContainer = new JPanel();
		this.panelContainer.setLayout(new BoxLayout(this.panelContainer, BoxLayout.Y_AXIS));
		JScrollPane scrollPaneContainer = new JScrollPane(this.panelContainer);
		scrollPaneContainer.setBorder(null);

		this.checkBoxIsAutoApply = new JCheckBox("IsAutoApply");
		this.buttonApply = new JButton("Apply");

		GroupLayout gl_mainContent = new GroupLayout(this);
		gl_mainContent.setAutoCreateContainerGaps(true);
		gl_mainContent.setAutoCreateGaps(true);
		this.setLayout(gl_mainContent);

		// @formatter:off
		gl_mainContent.setHorizontalGroup(gl_mainContent.createParallelGroup(Alignment.CENTER)
				.addComponent(scrollPaneContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
				.addGroup(gl_mainContent.createSequentialGroup()
						.addComponent(this.checkBoxIsAutoApply)
						.addGap(GroupLayout.PREFERRED_SIZE, 15, Short.MAX_VALUE)
						.addComponent(this.buttonApply, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)));
		
		gl_mainContent.setVerticalGroup(gl_mainContent.createSequentialGroup()
				.addComponent(scrollPaneContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
				.addGroup(gl_mainContent.createParallelGroup(Alignment.CENTER)
						.addComponent(this.checkBoxIsAutoApply)
						.addComponent(this.buttonApply)));
		// @formatter:on
	}

	private void initializeResources() {
		this.checkBoxIsAutoApply.setText(ControlsProperties.getString("String_AutoApply"));
		this.buttonApply.setText(CommonProperties.getString("String_Button_Apply"));
	}

	private void registerEvents() {
		this.formMap.addActiveLayersChangedListener(this.activeLayersChangedListener);
	}

	private void unregisterEvents() {
		this.formMap.removeActiveLayersChangedListener(this.activeLayersChangedListener);
	}

	private void activeLayersChanged(ActiveLayersChangedEvent e) {
		setActiveLayers(e.getNewActiveLayers(), this.formMap.getMapControl().getMap());
	}

	private void checkBoxIsAutoApplyCheckedChanged(ItemEvent e) {
		if (propertyControls != null && propertyControls.size() > 0) {
			for (AbstractLayerPropertyControl abstractLayerPropertyControl : propertyControls) {
				abstractLayerPropertyControl.setAutoApply(this.checkBoxIsAutoApply.isSelected());
			}
			if (this.checkBoxIsAutoApply.isSelected()) {
				this.buttonApply.setEnabled(false);
			}
		} else {
			this.buttonApply.setEnabled(false);
		}
	}

	private void buttonApplyClicked(ActionEvent e) {
		for (AbstractLayerPropertyControl abstractLayerPropertyControl : propertyControls) {
			abstractLayerPropertyControl.apply();
		}
		this.buttonApply.setEnabled(false);
	}

	private void setActiveLayers(Layer[] layers, Map map) {
		clearPropertyControls();

		if (layers != null && layers.length > 0) {
			final AbstractLayerPropertyControl[] propertyControls = this.propertyControlUtilties.getLayerPropertyControls(layers, map);

			SwingUtilities.invokeLater(new Runnable() {

				@Override
				public void run() {
					for (AbstractLayerPropertyControl abstractLayerPropertyControl : propertyControls) {
						addPropertyControl(abstractLayerPropertyControl);
					}
					panelContainer.updateUI();
				}
			});
		}
	}

	private void clearPropertyControls() {
		if (this.propertyControls != null && this.propertyControls.size() > 0) {
			for (AbstractLayerPropertyControl abstractLayerPropertyControl : propertyControls) {
				abstractLayerPropertyControl.removeLayerPropertyChangedListener(layerPropertyChangedListener);
			}

			this.panelContainer.removeAll();
			this.propertyControls.clear();
		}
	}

	private void addPropertyControl(AbstractLayerPropertyControl propertyControl) {
		if (propertyControl != null && this.propertyControls != null && !this.propertyControls.contains(propertyControl)) {
			this.propertyControls.add(propertyControl);
			this.panelContainer.add(propertyControl);
			propertyControl.addLayerPropertyChangedListener(layerPropertyChangedListener);
		}
	}
}
